package com.docmgmt.mvp.ragflow;

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.core.io.ClassPathResource;

import javax.crypto.Cipher;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.stream.Collectors;

/**
 * RAGFlow密码加密工具类
 * <p>
 * 实现与RAGFlow Python端完全相同的RSA加密逻辑 (api/utils/crypt.py)
 * <p>
 * 加密流程：
 * 1. 明文密码 → Base64编码
 * 2. Base64字符串 → RSA-PKCS1_v1_5加密（使用公钥）
 * 3. 加密结果 → Base64编码（最终输出）
 *
 * @author Dora
 */
@Slf4j
public class RAGFlowPasswordEncryptor {

    /**
     * RAGFlow公钥文件路径（classpath资源）
     */
    private static final String PUBLIC_KEY_PATH = "ragflow/public.pem";

    /**
     * RSA加密算法（PKCS1填充）
     */
    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";

    // 静态初始化Bouncy Castle Provider
    static {
        Security.addProvider(new BouncyCastleProvider());
        log.info("Bouncy Castle Provider已加载用于RAGFlow密码加密");
    }

    /**
     * 加密密码（与RAGFlow Python端兼容）
     * <p>
     * 实现逻辑等同于Python的crypt()函数：
     * <pre>
     * password_base64 = base64.b64encode(plaintext.encode('utf-8')).decode("utf-8")
     * encrypted = rsa_public_key.encrypt(password_base64.encode())
     * return base64.b64encode(encrypted).decode('utf-8')
     * </pre>
     *
     * @param plainPassword 明文密码
     * @return Base64编码的RSA加密密码
     * @throws RuntimeException 如果加密失败
     */
    public static String encryptPassword(String plainPassword) {
        try {
            // 步骤1：读取RSA公钥
            PublicKey publicKey = loadPublicKey();

            // 步骤2：明文密码 → Base64编码
            String passwordBase64 = Base64.getEncoder()
                    .encodeToString(plainPassword.getBytes(StandardCharsets.UTF_8));

            log.debug("密码Base64编码: {}", passwordBase64);

            // 步骤3：Base64字符串 → RSA加密
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] encryptedBytes = cipher.doFinal(passwordBase64.getBytes(StandardCharsets.UTF_8));

            // 步骤4：加密结果 → Base64编码（最终输出）
            String encryptedPassword = Base64.getEncoder().encodeToString(encryptedBytes);

            log.debug("密码加密成功，长度: {}", encryptedPassword.length());

            return encryptedPassword;

        } catch (Exception e) {
            log.error("RAGFlow密码加密失败", e);
            throw new RuntimeException("Failed to encrypt password for RAGFlow: " + e.getMessage(), e);
        }
    }

    /**
     * 从classpath加载RAGFlow公钥
     * <p>
     * 读取public.pem文件，解析X.509格式的RSA公钥
     *
     * @return RSA公钥
     * @throws Exception 如果公钥加载失败
     */
    private static PublicKey loadPublicKey() throws Exception {
        // 读取PEM文件内容
        ClassPathResource resource = new ClassPathResource(PUBLIC_KEY_PATH);

        if (!resource.exists()) {
            throw new IllegalStateException("RAGFlow公钥文件不存在: " + PUBLIC_KEY_PATH);
        }

        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) {

            // 读取PEM文件所有行
            String pemContent = reader.lines().collect(Collectors.joining("\n"));

            // 移除PEM标记（-----BEGIN PUBLIC KEY----- 和 -----END PUBLIC KEY-----）
            String publicKeyPEM = pemContent
                    .replace("-----BEGIN PUBLIC KEY-----", "")
                    .replace("-----END PUBLIC KEY-----", "")
                    .replaceAll("\\s", ""); // 移除所有空白字符

            // Base64解码得到公钥字节
            byte[] keyBytes = Base64.getDecoder().decode(publicKeyPEM);

            // 解析X.509格式的公钥
            X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(spec);

            log.info("RAGFlow RSA公钥加载成功: {}", PUBLIC_KEY_PATH);

            return publicKey;
        }
    }

    /**
     * 测试方法：验证加密功能
     * <p>
     * 使用示例密码测试加密流程
     *
     * @param args 命令行参数（未使用）
     */
    public static void main(String[] args) {
        String testPassword = "q145144139";

        log.info("========== RAGFlow密码加密测试 ==========");
        log.info("明文密码: " + testPassword);

        try {
            String encrypted = encryptPassword(testPassword);
            log.info("加密密码: " + encrypted);
            log.info("加密密码长度: " + encrypted.length());
            log.info("========== 加密成功！==========");
        } catch (Exception e) {
            log.error("加密失败: " + e.getMessage(), e);
        }
    }
}
